package com.peralex.utilities.ui.titlebar;

import java.awt.Color;
import java.awt.Font;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.util.ArrayList;
import java.util.List;

import javax.swing.Box;
import javax.swing.JFrame;
import javax.swing.UIManager;
import javax.swing.border.Border;

import com.peralex.utilities.ui.images.CloseIcon;
import com.peralex.utilities.ui.images.IconManager;

/**
 * Title bar with minimize/maximize and lock/unlock and close buttons.
 * The buttons can be set to visible or invisible.
 * 
 * @author Noel Grandin
 * @author Jaco
 */
public class TitleBar extends javax.swing.JPanel
{
	private final List<ITitleBarListener> oTitleBarEventListeners = new ArrayList<ITitleBarListener>();
	private boolean bCloseable = true;
	private boolean bLockable = true;
	private boolean bMinimizeable = true;
	
  private final Color backgroundColor1;
  private final Color backgroundColor2;
	
	private static final String oCollapseIconURL = "/com/peralex/utilities/ui/images/collapse.png";
	private static final String oExpandIconURL = "/com/peralex/utilities/ui/images/expand.png";
	private static final String oLockClosedIconURL = "/com/peralex/utilities/ui/images/lock_closed.gif";
	private static final String oLockOpenIconURL = "/com/peralex/utilities/ui/images/lock_open.gif";
	
	/** Creates new form cTitleBar */
	public TitleBar()
	{
		this("Title");
	}
	
	/** Creates new form cTitleBar */
	public TitleBar(String sTitle)
	{
		// set up defaults that are close to the OS colours
		backgroundColor1 = getSafeColor("InternalFrame.activeTitleBackground", new Color(49, 121, 242));
		backgroundColor2 = getSafeColor("InternalFrame.activeTitleGradient", new Color(198, 211, 247));
        
		initComponents();
		oTitleLabel.setFont(oTitleLabel.getFont().deriveFont(Font.BOLD));
		oTitleLabel.setText(sTitle);
		setIcons();
    setBackground(null);

    // add a couple of pixels worth of space after the last button
    java.awt.GridBagConstraints gridBagConstraints = new java.awt.GridBagConstraints();
    gridBagConstraints.gridx = 4;
    gridBagConstraints.gridy = 0;
    add(Box.createHorizontalStrut(2), gridBagConstraints);
    
    /* Tell the Swing paint code that we paint every pixel ourselves, so it doesn't need to
     * paint a background. */
    setOpaque(false);
	}

  private static Color getSafeColor(String uiKey, Color fallBack)
	{
		Color color = UIManager.getColor(uiKey);
		if (color == null)
		{
			color = fallBack;
		}
		return color;
	}
  
	private void setIcons()
	{
		final float scalingFactor = 0.7f;
		oCloseButton.setIcon(IconManager.getSizedFor(CloseIcon.INSTANCE, oTitleLabel, scalingFactor));
		oLockToggleButton.setIcon(IconManager.getSizedFor(oLockOpenIconURL, oTitleLabel, scalingFactor));
		oLockToggleButton.setSelectedIcon(IconManager.getSizedFor(oLockClosedIconURL, oTitleLabel, scalingFactor));
		oMinimizeToggleButton.setIcon(IconManager.getSizedFor(oCollapseIconURL, oTitleLabel, scalingFactor));
		oMinimizeToggleButton.setSelectedIcon(IconManager.getSizedFor(oExpandIconURL, oTitleLabel, scalingFactor));
	}
	
	/** This method is called from within the constructor to
	 * initialize the form.
	 * WARNING: Do NOT modify this code. The content of this method is
	 * always regenerated by the Form Editor.
	 */
  // <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:initComponents
  private void initComponents()
  {
    java.awt.GridBagConstraints gridBagConstraints;

    oTitleLabel = new javax.swing.JLabel();
    oLockToggleButton = new javax.swing.JToggleButton();
    oMinimizeToggleButton = new javax.swing.JToggleButton();
    oCloseButton = new javax.swing.JToggleButton();

    setLayout(new java.awt.GridBagLayout());

    setBorder(javax.swing.BorderFactory.createEmptyBorder(0, 0, 0, 0));
    setOpaque(false);
    oTitleLabel.setForeground(new java.awt.Color(255, 255, 255));
    oTitleLabel.setText("Title");
    oTitleLabel.setBorder(javax.swing.BorderFactory.createEmptyBorder(0, 0, 0, 0));
    gridBagConstraints = new java.awt.GridBagConstraints();
    gridBagConstraints.gridx = 0;
    gridBagConstraints.gridy = 0;
    gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
    gridBagConstraints.weightx = 1.0;
    gridBagConstraints.insets = new java.awt.Insets(1, 5, 1, 1);
    add(oTitleLabel, gridBagConstraints);

    oLockToggleButton.setAlignmentX(0.5F);
    oLockToggleButton.setBorderPainted(false);
    oLockToggleButton.setFocusPainted(false);
    oLockToggleButton.setFocusable(false);
    oLockToggleButton.setIconTextGap(0);
    oLockToggleButton.setMargin(new java.awt.Insets(1, 1, 1, 1));
    oLockToggleButton.addActionListener(new java.awt.event.ActionListener()
    {
      public void actionPerformed(java.awt.event.ActionEvent evt)
      {
        oLockToggleButtonActionPerformed(evt);
      }
    });

    gridBagConstraints = new java.awt.GridBagConstraints();
    gridBagConstraints.gridx = 1;
    gridBagConstraints.gridy = 0;
    gridBagConstraints.insets = new java.awt.Insets(2, 1, 2, 1);
    add(oLockToggleButton, gridBagConstraints);

    oMinimizeToggleButton.setAlignmentX(0.5F);
    oMinimizeToggleButton.setBorderPainted(false);
    oMinimizeToggleButton.setFocusPainted(false);
    oMinimizeToggleButton.setFocusable(false);
    oMinimizeToggleButton.setIconTextGap(0);
    oMinimizeToggleButton.setMargin(new java.awt.Insets(1, 1, 1, 1));
    oMinimizeToggleButton.addActionListener(new java.awt.event.ActionListener()
    {
      public void actionPerformed(java.awt.event.ActionEvent evt)
      {
        oMinimizeToggleButtonActionPerformed(evt);
      }
    });

    gridBagConstraints = new java.awt.GridBagConstraints();
    gridBagConstraints.gridx = 2;
    gridBagConstraints.gridy = 0;
    gridBagConstraints.insets = new java.awt.Insets(2, 1, 2, 1);
    add(oMinimizeToggleButton, gridBagConstraints);

    oCloseButton.setAlignmentX(0.5F);
    oCloseButton.setBorderPainted(false);
    oCloseButton.setFocusPainted(false);
    oCloseButton.setFocusable(false);
    oCloseButton.setIconTextGap(0);
    oCloseButton.setMargin(new java.awt.Insets(1, 1, 1, 1));
    oCloseButton.addActionListener(new java.awt.event.ActionListener()
    {
      public void actionPerformed(java.awt.event.ActionEvent evt)
      {
        oCloseButtonActionPerformed(evt);
      }
    });

    gridBagConstraints = new java.awt.GridBagConstraints();
    gridBagConstraints.gridx = 3;
    gridBagConstraints.gridy = 0;
    gridBagConstraints.insets = new java.awt.Insets(2, 1, 2, 1);
    add(oCloseButton, gridBagConstraints);

  }// </editor-fold>//GEN-END:initComponents

	private void oMinimizeToggleButtonActionPerformed(@SuppressWarnings("unused") java.awt.event.ActionEvent evt)//GEN-FIRST:event_oMinimizeToggleButtonActionPerformed
	{//GEN-HEADEREND:event_oMinimizeToggleButtonActionPerformed
		if (bMinimizeable)
		{
			if (oMinimizeToggleButton.isSelected())
			{
				notifyMinimizeListeners();
			}
			else
			{
				notifyMaximizeListeners();
			}
		}
	}//GEN-LAST:event_oMinimizeToggleButtonActionPerformed

	private void oLockToggleButtonActionPerformed(@SuppressWarnings("unused") java.awt.event.ActionEvent evt)//GEN-FIRST:event_oLockToggleButtonActionPerformed
	{//GEN-HEADEREND:event_oLockToggleButtonActionPerformed
		if (bLockable)
		{
			if (oLockToggleButton.isSelected())
			{
				notifyLockListeners();
			}
			else
			{
				notifyUnlockListeners();
			}
		}
	}//GEN-LAST:event_oLockToggleButtonActionPerformed

	private void oCloseButtonActionPerformed(@SuppressWarnings("unused") java.awt.event.ActionEvent evt)//GEN-FIRST:event_oCloseButtonActionPerformed
	{//GEN-HEADEREND:event_oCloseButtonActionPerformed
		if (bCloseable)
		{
			notifyCloseListeners();
		}
	}//GEN-LAST:event_oCloseButtonActionPerformed

	/**
	 * Getter for property Title.
	 * @return Value of property Title.
	 */
	public String getTitle()
	{
		return oTitleLabel.getText();
	}
	
	/**
	 * Setter for property Title.
	 * @param sTitle New value of property Title.
	 */
	public void setTitle(String sTitle)
	{
		oTitleLabel.setText(sTitle);
	}
	
	/**
	 * Setter for property Title Font.
	 * @param oFont New value of property Title Font.
	 */
	public void setTitleFont(Font oFont)
	{
		oTitleLabel.setFont(oFont);
		setIcons();
	}
	
	/**
	 * Setter for property oTitleColour.
	 * @param oTitleColour New value of property oTitleColour.
	 */
	public void setTitleColour(Color oTitleColour)
	{
		oTitleLabel.setForeground(oTitleColour);
	}
	
	public void setCloseable(boolean bCloseable)
	{
		this.bCloseable = bCloseable;
		this.oCloseButton.setVisible(bCloseable);
	}
	
	public void setLockable(boolean bLockable)
	{
		this.bLockable = bLockable;
		this.oLockToggleButton.setVisible(bLockable);
	}
	
	public void setMinimizable(boolean bMinimizeable)
	{
		this.bMinimizeable = bMinimizeable;
		this.oMinimizeToggleButton.setVisible(bMinimizeable);
	}
	
	public void setMinimized()
	{
		this.oMinimizeToggleButton.setSelected(true);
		notifyMinimizeListeners();
	}
	
	public void setMaximized()
	{
		this.oMinimizeToggleButton.setSelected(false);
		notifyMaximizeListeners();
	}
	
	public void addTitleBarListener(ITitleBarListener oTitleBarListener)
	{
		oTitleBarEventListeners.add(oTitleBarListener);
	}
	
	public void removeTitleBarListener(ITitleBarListener oTitleBarListener)
	{
		oTitleBarEventListeners.remove(oTitleBarListener);
	}
	
	private void notifyMinimizeListeners()
	{
		for (ITitleBarListener listener : oTitleBarEventListeners)
		{
			listener.minimizeEvent();
		}
	}
	
	private void notifyMaximizeListeners()
	{
		for (ITitleBarListener listener : oTitleBarEventListeners)
		{
			listener.maximizeEvent();
		}
	}

	private void notifyCloseListeners()
	{
		for (ITitleBarListener listener : oTitleBarEventListeners)
		{
			listener.closeEvent();
		}
	}

	private void notifyLockListeners()
	{
		for (ITitleBarListener listener : oTitleBarEventListeners)
		{
			listener.lockEvent();
		}
	}

	private void notifyUnlockListeners()
	{
		for (ITitleBarListener listener : oTitleBarEventListeners)
		{
			listener.unlockEvent();
		}
	}
	
	@Override
	public void paintComponent(Graphics g)
	{
		final Graphics2D g2D = (Graphics2D)g;
		final Paint oldPaint = g2D.getPaint();
		
		final GradientPaint oGradientPaint = new GradientPaint(
				0, 0, backgroundColor1,
		    (int)(getWidth()*0.75), 0, backgroundColor2);
		g2D.setPaint(oGradientPaint);
		
		final Border border = getBorder();
		if (border!=null) {
			final java.awt.Insets insets = getBorder().getBorderInsets(this);
			g2D.fillRect(insets.left, insets.top, 
					getWidth()-insets.left-insets.right, 
					getHeight()-insets.top-insets.bottom);
		} else {
			g2D.fillRect(0, 0, getWidth(), getHeight());
		}
		
		// restore old paint
		g2D.setPaint(oldPaint);
		
		// now paint the normal stuff
		super.paintComponent(g);
	}
	
  // Variables declaration - do not modify//GEN-BEGIN:variables
  private javax.swing.JToggleButton oCloseButton;
  private javax.swing.JToggleButton oLockToggleButton;
  private javax.swing.JToggleButton oMinimizeToggleButton;
  private javax.swing.JLabel oTitleLabel;
  // End of variables declaration//GEN-END:variables
	
	public static void main(String[] args)
	{
		try
		{
			UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
    }
		catch (Exception ignoreEx) {}
		
		final TitleBar blockControl = new TitleBar();

		final JFrame frame = new JFrame("cTitleBar Test Frame");
		frame.getContentPane().add(blockControl);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.pack();
		frame.setSize(400, 300);
		frame.setVisible(true);
	}
}
